iT邦幫忙

2024 iThome 鐵人賽

DAY 3
0

對於平常使用 UIKit 的我來說,這個專案結構對我來說有點認識,又有一點不認識😂。我認為在 SwiftUI 的開發旅程中,理解專案的基本結構是非常重要的一步。在今天的挑戰中,我們來認識 SwiftUI 專案的主要組成部分,並了解如何管理和使用這些資源。

SwiftUI 專案的基本結構

在 Xcode 中,建立新的 SwiftUI 專案時,會自動產生一些檔案和資料夾。讓我們來好好看一下這些檔案是什麼用途吧!
https://ithelp.ithome.com.tw/upload/images/20240917/20168462p3HUgC9boq.jpg

1. App.swift

HandyInventory_ironApp.swift 是一個 Swift 檔,由專案名 + App 組合而成。它定義 SwiftUI 專案的進入點,App 的啟動和生命週期都可以在這裡控制,它包含一個 App 協議的結構體(struct)。@main 標記代表 App 的進入點。body 定義 App 的初始場景,一般來說,這個場景會有一個主畫面,例如 ContentView。

import SwiftUI

@main
struct HandyInventoryApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

這段程式碼表示當 App 啟動時,會顯示 ContentView 的畫面。

2. ContentView.swift

ContentView.swift 是 SwiftUI 專案中主要實作 UI 的檔案。這邊的程式碼定義 SwiftUI 如何使用 View 協議來建構簡單靈活的界面。下面這段程式碼表示一個 Hello, world! 文字在 UI 上,並透過 Day2 提到的右邊的預覽視窗顯示。

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
    }
}

#Preview {
    ContentView()
}

ContentView 程式碼介紹

在這個範例中,我們看到 ContentView 是使用 struct 來定義的,而且並不是繼承 UIView ,而是實作一個名為 View 的 protocol ,這代表它符合 View 協議。這裡的 body 屬性是唯一且必須的部分,而我們可以發現 body 其實使用了一個很特別的型別 - some view 。在 Apple 提供的文件中有描述 some view 中的 some 所代表的是不透明的類型,也就是 Opaque Types ,發音念「歐配可」。

參考資料:Declaring a custom view

Opaque Types
所謂不透明的類型,可以把它視為 reverse 的泛型,為什麼呢?讓我們來看一下解釋:
Swift 中的函數有個很好的例子 max,它會傳回兩個輸入參數中的最大值,而這兩個參數的類型是未知的。

func max<T>(_ x: T, _ y: T) -> T where T: Comparable

這個函式規定兩個輸入參數必須具有相同的型別T,但我們並不知道 T 具體是哪種型別。然而,我們知道這些參數可以使用 > 運算子來比較。雖然在定義這個函式時,我們不清楚 T 是什麼,但在實際使用時,透過程式碼的上下文,我們可以推斷出輸入及輸出的具體類型。

與此相對應,當我們使用不透明類型時,我們不需要知道 View 內部的具體運作細節,這些細節只有編譯器會知道。換句話說,不透明類型可以返回一個特定的型別,但無需在定義時明確指定這個型別的細節。

有興趣的人可以參考下方的參考文獻,我覺得他們的舉例和講解都很不錯。第二個和第三個連結是使用健達出奇蛋來舉例 some view 的意思,第一個連結是一個 Youtube 教學 - ChaoCode,她實際使用 Playground 操作一遍,解釋什麼是 some view ,對我來說 ChaoCode 的解釋比較好懂XD。

參考資料:

Preview
在 SwiftUI 中,預覽功能(Preview)能夠即時顯示我們的 UI 變化,這是透過 #Preview 區塊來實現的。這段程式碼不會成為送審到 App Store 的一部分,但可以讓我們在 Xcode 中即時查看設計效果。

為什麼 SwiftUI 使用 Struct 來定義 Views?

SwiftUI 之所以使用 Struct 來定義視圖,有幾個重要原因:

  1. 減少意外發生的可能性:Class 是 Reference type,而 Struct 是 Value type。簡單來說,使用 Struct 可以避免一些預期之外的變動,讓我們更容易掌握資料的變化。這樣的設計,讓 Struct 在追蹤資料變更時比 Class 更加穩定。SwiftUI 鼓勵我們採用更「功能性」的設計方式。使用 Struct 來定義視圖,就是這種功能性編程的重要一環。
  2. 提高效能:Struct 不僅比 Class 更簡單、也更快。用 Class 來建立 Views 的時候,會繼承很多屬性和方法,這讓 UI 變得很重、很複雜。但是用 Struct 來建立視圖就不一樣了。Struct 不會繼承任何東西,只包含你自己定義的內容。而且用 Struct 的話,因為它的變化比較容易被追蹤,所以在效能上也有優勢。
  3. 避免記憶體洩漏:使用 Class 的時候,有時候會遇到記憶體洩漏的問題,因為 Class 是參考型別,容易出現一些記憶體沒有被正確釋放的情況。相對來說,使用 Struct 這種值型別,可以讓程式更加安全,避免這類問題。

參考資料:Why does SwiftUI define views using Struct?

3. Persistence.swift

Persistence.swift 和 HandyInventory_iron.xcdatamodeld 都和 Core Data 相關,用來在本機上儲存資料,其背後操作的雖然仍是 SQLite,但它簡化資料庫的處理,讓不了解 SQL 指令的人也可以快速的為 App 建立並使用資料庫。

4. Assets.xcassets

Assets.xcassets 資料夾用於管理 App 中的圖像和顏色資源。所有的 icon、圖片和顏色資源都可以放在這裡,並在 SwiftUI 中方便地引用。

5. Preview Content

SwiftUI 的即時預覽功能是它一個強大的功能,Preview Content 資料夾是用來放預覽時所需的內容,如測試資料(模擬 API 回傳的 Json)或圖片。使開發過程中,讓我們可以隨時看和調整 UI 的外觀和行為。

總結

SwiftUI 和 UIKit 的專案架構真的不太一樣,我們以前所熟悉的某些東西都被置換成新的東西,還出現了與 UIView 不同的型別。不過這些新東西的出現,真的是簡化很多開發的步驟,使用起來也更方便、快速了呢!在撰寫這篇文章的時候,參考了蠻多不同的文章,為了避免各種大混雜,我直接按照章節將參考文獻放在裡面。那我們就明天再見囉!


上一篇
Day 2: 和 SwiftUI 打招呼,開啟新專案
下一篇
Day 4: 認識 SwiftUI 的常用 UI 元件
系列文
用 SwiftUI 掌控家庭日用品庫存30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言